package com.dwxt.common.aop;


import com.dwxt.common.annotation.ValidateFiled;
import com.dwxt.common.annotation.ValidateGroup;
import com.dwxt.common.base.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author: YanLong
 * @Description:
 * @Date: Created in 13:41 2018/12/4
 */
@Component
@Aspect
@Slf4j
public class ValidateAspectHandel {

    /**
     * 使用AOP对使用了ValidateGroup的方法进行代理校验
     *
     * @throws Throwable
     */
    //@SuppressWarnings({"finally", "rawtypes"})
    @Around("@annotation(com.dwxt.common.annotation.ValidateGroup)")
    public Object validateAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();     //方法的参数
        String methodName = joinPoint.getSignature().getName();
        Object target = joinPoint.getTarget();
        Method method = getMethodByClassAndName(target.getClass(), methodName);    //得到拦截的方法
        ValidateGroup an = (ValidateGroup) getAnnotationByMethod(method, ValidateGroup.class);
        Object flag = validateFiled(an.fileds(), args, method);
        if (flag instanceof Boolean && (Boolean) flag) {
            //System.out.println("验证通过");
            return joinPoint.proceed();
        } else {  //这里使用了Spring MVC ，所有返回值应该为String或ModelAndView
            //System.out.println("验证未通过");
            Class returnType = method.getReturnType();  //得到方法返回值类型
            if (returnType == String.class) { //如果返回值为Stirng
                return "/error.jsp";        //返回错误页面
            } else if (returnType == ModelAndView.class) {
                return new ModelAndView("/error.jsp");//返回错误页面
            } else if (returnType == BaseResult.class) {
                return BaseResult.build(1001, "请确认填写正确!(" + flag + ")", null);
                //return BaseResult.build(1001, "parameter is wrong!");
            } else {  //当使用Ajax的时候 可能会出现这种情况
                return null;
            }
        }
    }

    /**
     * 验证参数是否合法
     */
    public Object validateFiled(ValidateFiled[] valiedatefiles, Object[] args, Method method) throws NoSuchMethodException,
            IllegalAccessException, InvocationTargetException {
        for (ValidateFiled validateFiled : valiedatefiles) {
            Object arg;
            String parameterName = null;
            if ("".equals(validateFiled.filedName())) {
                DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
                String[] parameterNames = discover.getParameterNames(method);
                parameterName = parameterNames[validateFiled.index()];
                arg = args[validateFiled.index()];
            } else {
                arg = getFieldByObjectAndFileName(args[validateFiled.index()],
                        validateFiled.filedName());
            }
            //任一个选项为true.代表校验不通过
            if (isNull(validateFiled, arg) || gtMaxLength(validateFiled, arg) || ltMinLength(validateFiled, arg)
                    || gtMaxValue(validateFiled, arg) || ltMinValue(validateFiled, arg) || notRegStr(validateFiled, arg)) {
                return parameterName == null ? validateFiled.filedName() : parameterName;
                //return false;
            }
        }
        return true;
    }

    public boolean notRegStr(ValidateFiled validateFiled, Object arg) {
        if (!"".equals(validateFiled.regStr())) { //判断正则
            if (arg instanceof String) {
                if (!((String) arg).matches(validateFiled.regStr())) {
                    log.error("字段: {}, 值为 {}， 不符合正则", validateFiled.filedName(), arg);
                    return true;
                }
            } else {
                return true;
            }
        }
        return false;
    }

    public boolean ltMinValue(ValidateFiled validateFiled, Object arg) {

        if (validateFiled.minVal() != -1 && arg instanceof Integer && (Integer) arg < validateFiled.minVal()) {   //判断数值最小值
            log.error("字段: {}, 值为 {}， 值小于最小值", validateFiled.filedName(), arg);
            return true;
        } else if (validateFiled.minVal() != -1 && arg instanceof Double && (Double) arg < validateFiled.minVal()) {
            return true;
        }
        return false;
    }

    public boolean gtMaxValue(ValidateFiled validateFiled, Object arg) {
        if (validateFiled.maxVal() != -1 && arg instanceof Double && (double) arg > validateFiled.maxVal()) {   //判断数值最大值
            log.error("字段: {}, 值为 {}， 值大于最大值", validateFiled.filedName(), arg);
            return true;
        } else if (validateFiled.maxVal() != -1 && arg instanceof Integer && (Integer) arg > validateFiled.maxVal()) {
            return true;
        }
        return false;
    }

    public boolean ltMinLength(ValidateFiled validateFiled, Object arg) {
        if (validateFiled.minLen() > 0 && ((String) arg).length() < validateFiled.minLen()) {      //判断字符串最小长度
            log.error("字段: {}, 值为 {}， 长度不够", validateFiled.filedName(), arg);
            return true;
        }
        return false;
    }

    public boolean gtMaxLength(ValidateFiled validateFiled, Object arg) {
        if (validateFiled.maxLen() > 0 && ((String) arg).length() > validateFiled.maxLen()) {      //判断字符串最大长度
            log.error("字段: {}, 值为 {}， 长度超过限制", validateFiled.filedName(), arg);
            return true;
        }
        return false;
    }

    public boolean isNull(ValidateFiled validateFiled, Object arg) {
        if (validateFiled.notNull() && (arg == null || "".equals(arg))) {        //判断参数是否为空
            log.error("字段: {}, 为null或者为空字符串", validateFiled.filedName());
            return true;
        }
        return false;
    }

    /**
     * 根据对象和属性名得到 属性
     */
    public Object getFieldByObjectAndFileName(Object targetObj, String fileName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        String[] tmp = fileName.split("\\.");
        Object arg = targetObj;
        for (int i = 0; i < tmp.length; i++) {
            Method method = arg.getClass().
                    getMethod(getGetterNameByFiledName(tmp[i]));
            arg = method.invoke(arg);
        }
        return arg;
    }

    /**
     * 根据属性名 得到该属性的getter方法名
     */
    public String getGetterNameByFiledName(String fieldName) {
        return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }

    /**
     * 根据目标方法和注解类型  得到该目标方法的指定注解
     */
    public Annotation getAnnotationByMethod(Method method, Class annoClass) {
        Annotation[] all = method.getAnnotations();
        for (Annotation annotation : all) {
            if (annotation.annotationType() == annoClass) {
                return annotation;
            }
        }
        return null;
    }

    /**
     * 根据类和方法名得到方法
     */
    public Method getMethodByClassAndName(Class c, String methodName) {
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                return method;
            }
        }
        return null;
    }

}

